#include <iostream>
#include <string>
#include <memory>
#include <ctime>
#include "Protocol.hpp"
#include "Socket.hpp"
#include "InterAddr.hpp"

using namespace protocol_ns;
using namespace socket_ns;

void Usage(std::string proc)
{
    std::cout << "Usage\n\t" << proc << " local_ip local_port\n"
              << std::endl;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(1);
    }

    std::string serverip = argv[1];
    uint16_t serverport = std::stoi(argv[2]);

    InterAddr serveraddr(serverip, serverport);
    Factory factory;
    std::unique_ptr<Socket> cli = std::make_unique<TcpSocket>();
    bool res = cli->BuidClientSocket(serveraddr);
    std::string inbuffer;
    while (res)
    {
        // 1. 构建一个请求

        std::string str;
        // for (int i = 0; i < 5; i++)
        // {
        //     auto req = factory.BuildRequest();
        //     // 2. 对请求进行序列化

        //     std::string send_str;
        //     req->Serialize(&send_str);

        //     std::cout << "Serialize:\n"
        //               << send_str << std::endl;

        //     // 3. 添加长度报头
        //     send_str = Encode(send_str);
        //     std::cout << "Encode:\n"
        //               << send_str << std::endl;
        //     str += send_str;
        // }
        sleep(1);
        auto req = factory.BuildRequest();
        // 2. 对请求进行序列化

        std::string send_str;
        req->Serialize(&send_str);

        std::cout << "Serialize:\n"
                    << send_str << std::endl;

        // 3. 添加长度报头
        send_str = Encode(send_str);
        std::cout << "Encode:\n"
                    << send_str << std::endl;
            str += send_str;
        // 4. "len"/r/n"{   }"/r/n"
        // 发数据
        cli->Send(str);

        // 5. 读取应答
        int n = cli->Recv(&inbuffer);
        if (n <= 0)
        {
            break;
        }
        // 根据报头长度拿到数据
        std::string package = Decode(inbuffer);
        if (package.empty())
            continue;

        // 6. 这里能保证package一定是一个完成的应答
        auto resp = factory.BuildResponse();
        // 6.1 反序列化
        resp->Deserialize(package);

        // 7. 拿到了结构化的应答
        std::cout << resp->_result << "[" << resp->_code << "]" << std::endl;
    }
    return 0;
}


// 如果客户端的监听套接字被设置为了非阻塞状态，那么可能connection的时候就可能再还没有建立完成连接就返回了
// 于是就会返回EINPROGRESS错误码，如果要将客户端的监听套接字设置为非阻塞状态，则需要对监听套接字进行判断
// 如果返回的是EINPROGRESS那么就将其添加到select/poll/epoll中进行等待，如果写事件就绪了那么就说明连接完成了，就可以进行发送数据了。

// #include <sys/types.h>
// #include <sys/socket.h>
// #include <netinet/in.h>
// #include <arpa/inet.h>
// #include <fcntl.h>
// #include <unistd.h>
// #include <errno.h>
// #include <stdio.h>
// #include <string.h>

// // 设置套接字为非阻塞模式的函数
// void setNonBlocking(int sockfd) {
//     int flags = fcntl(sockfd, F_GETFL, 0);
//     fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
// }

// int main() {
//     int sockfd = socket(AF_INET, SOCK_STREAM, 0);
//     if (sockfd < 0) {
//         perror("socket error");
//         return 1;
//     }

//     setNonBlocking(sockfd);

//     struct sockaddr_in serv_addr;
//     memset(&serv_addr, 0, sizeof(serv_addr));
//     serv_addr.sin_family = AF_INET;
//     serv_addr.sin_port = htons(8080);
//     inet_pton(AF_INET, "127.0.0.1", &serv_addr.sin_addr);

//     int ret = connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
//     if (ret < 0 && errno == EINPROGRESS) {
//         // 连接正在进行中，使用select等待套接字变为可写
//         fd_set writefds;
//         FD_ZERO(&writefds);
//         FD_SET(sockfd, &writefds);

//         struct timeval tv;
//         tv.tv_sec = 5; // 设置超时时间
//         tv.tv_usec = 0;

//         ret = select(sockfd + 1, NULL, &writefds, NULL, &tv);
//         if (ret > 0 && FD_ISSET(sockfd, &writefds)) {
//             // 套接字可写，连接成功
//             int err;
//             socklen_t len = sizeof(err);
//             getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &err, &len);
//             if (err == 0) {
//                 printf("Connected successfully\n");
//             } else {
//                 printf("Connection failed: %s\n", strerror(err));
//                 close(sockfd);
//                 return 1;
//             }
//         } else {
//             // select出错或超时
//             perror("select error or timeout");
//             close(sockfd);
//             return 1;
//         }
//     } else if (ret < 0) {
//         perror("connect error");
//         close(sockfd);
//         return 1;
//     } else {
//         // 立即连接成功
//         printf("Connected successfully\n");
//     }

//     // 此处可以进行后续的读写操作
//     close(sockfd);
//     return 0;
// }